#ifndef MODULE_H
#define MODULE_H

#include <boost/shared_ptr.hpp>
#include <string>
#include "errors.h"
#include "lexer.h"
#include "token.h"
#include "ast.h"

class Package;

class Module
{
public:
   typedef boost::shared_ptr<Module> Ptr;
   typedef std::vector<Ptr> Vector;

protected:
   Package& _package;
   Errors _errors;
   Lexer _lexer;

   std::string _name;
   std::string _path;

   ASTImport::Vector _imports;
   ASTTypeDefinition::Vector _types;
   Token::Ptr _current;

public:
	Module( Package& package, const std::string& name, const std::string& path );

   bool parse();
   bool resolve_base_types();
   bool type_check();
   void resolve_type( const ASTBaseType& type, ASTTypeDefinition::Vector& list );
   void resolve_local_type( const std::string& name, ASTTypeDefinition::Vector& list );
   void print( uint32_t level );

protected:
   void next_token();

   void parse_import();
   void parse_enum();
   void parse_type_def();
   void parse_generics( ASTClass::Ptr ast );
   void parse_implements( ASTClass::Ptr ast );
   void parse_generic_constraint( ASTClass::Ptr ast );

   ASTBaseType::Ptr parse_base_type();
   ASTType::Ptr parse_type();
   ASTLiteral::Ptr parse_literal();
   ASTMember::Ptr parse_member();
   ASTMethod::Ptr parse_method();
   ASTBlock::Ptr parse_block();
   ASTCommand::Ptr parse_command();

   ASTVariable::Ptr parse_variable();
   ASTIf::Ptr parse_if();

   ASTExpr::Ptr parse_expr();
   ASTExpr::Ptr parse_paren_expr();
   ASTArray::Ptr parse_array();
   ASTUnary::Ptr parse_unary_expr();
   ASTBinary::Ptr parse_binary_expr( ASTExpr::Ptr lhs );
   ASTExpr::Ptr parse_base_expr();
   ASTArrayIndex::Ptr parse_array_index( ASTExpr::Ptr array );
   ASTCall::Ptr parse_call( ASTExpr::Ptr method );
   ASTSuperCall::Ptr parse_super_call();
   ASTObjectCall::Ptr parse_object_call( ASTExpr::Ptr object );
   ASTTypeIdentifier::Ptr parse_type_member();

   ASTExpr::VectorPtr parse_expr_list();
   ASTExpr::VectorPtr parse_arg_list();
   ASTTypeIdentifier::VectorPtr parse_param_list();

   bool is_binary_op();
};

#endif // MODULE_H
